#include "connection.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QStringList>
#include <QTime>
#include <QTimer>

Connection::Connection(QNetworkProxy proxy, int porta) : QObject()
{
    qsrand(QTime::currentTime().msec() * QTime::currentTime().hour() * QTime::currentTime().minute());

    this->paises = new ListaPaises ();

    this->objetivos = new ListaObjetivos();

    this->cores = new Cores();

    this->porta_conexao = porta;
    this->server = new QTcpServer();
    this->server->setProxy(proxy);
    this->server->listen(QHostAddress::Any, 50000);
    this->visualizador = new VisualizadorConexoes();
    this->visualizador->show();
    connect (this->server, SIGNAL(newConnection()), this, SLOT(setSocket()));
    connect (this->visualizador, SIGNAL(finalizarEspera()), this, SLOT(terminarEspera()));
    connect (this, SIGNAL(mudancaTropa(QString)), this->paises, SLOT(mudancaTropaPais(QString)));
    connect (this, SIGNAL(ataqueDeclarado(QString)), this->paises, SLOT(processarAtaque(QString)));
    connect (this->paises, SIGNAL(tropasAlteradas(QString)), this, SLOT(sendMessage(QString)));
    connect (this->paises, SIGNAL(paisDerrotado(QString)), this, SLOT(sendMessage(QString)));
    connect (this->paises, SIGNAL(sorteioDados(QString)), this, SLOT(sendMessage(QString)));
    connect (this, SIGNAL(turnoEncerrado(QString)), this, SLOT(passarVez(QString)));
    connect (this, SIGNAL(verificarObjetivo(QString)), this, SLOT (checarObjetivo(QString)));
    continuar = true;

    this->ultimo_jogador = 0;

    this->mensageiro = new EnviadorMensagem(this);
    this->mensageiro->start(QThread::NormalPriority);
}

void Connection::setSocket()
{
    if (sockets_list.size() < 6) {
        sockets_list.append(new Participante(this->server->nextPendingConnection()));
        connect (this->sockets_list.at(this->sockets_list.size()-1)->socket, SIGNAL(readyRead()), this, SLOT(pacoteDisponivel()));
        this->sendMessage(this->sockets_list.at(this->sockets_list.size()-1), "<tipo>rtn");
    }
}

void Connection::sendMessage(Participante* participante, QString texto)
{
    Mensagem* mensagem = new Mensagem(texto, participante->socket);
    this->mensagens.append(mensagem);
}

void Connection::sendMessage(QString texto)
{
    QList<QTcpSocket*> lista;
    for (int i = 0; i < this->sockets_list.size(); i++)
        lista.append(this->sockets_list.at(i)->socket);
    Mensagem* mensagem = new Mensagem(texto,lista);
    this->mensagens.append(mensagem);
}

void Connection::sendMessage(Mensagem* mensagem)
{
    QByteArray data;
    QDataStream out (&data, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_0);
    out << mensagem->mensagem;
    for (int i = 0; i < mensagem->destinatarios.size(); i++) {
        if (!mensagem->destinatarios.at(i)->isOpen()) {
            mensagem->destinatarios.at(i)->open(QIODevice::ReadWrite);
        }
        mensagem->destinatarios.at(i)->write(data);
    }
}

void Connection::pacoteDisponivel ()
{
    while (this->hasDataToRead()) {

        QTcpSocket* sender_socket = dynamic_cast<QTcpSocket*>(sender());
        QDataStream in(sender_socket);
        in.setVersion(QDataStream::Qt_4_0);
        QString text;
        in >> text;

        //cht - pacote de mensagem de chat
        if (text.startsWith("<tipo>cht"))
            this->sendMessage(text);

        //nom - pacote contendo o nome do jogador
        else if (text.startsWith("<tipo>nom")) {
            int i;
            for (i = 0; i < sockets_list.size(); i++) {

                if (this->sockets_list.at(i)->socket == sender()) {
                    break;
                }
            }

            this->visualizador->adicionaJogador(text.right(text.size() - 15));
            this->sockets_list.at(i)->nome_jogador = text.right(text.size() - 15);
        }

        //mtp - pacote de mudança de tropa
        else if (text.startsWith("<tipo>mtp"))
            emit this->mudancaTropa(text.right(text.size() - 9));

        //atq - pacote de aviso de ataque declarado
        else if (text.startsWith("<tipo>atq"))
            emit this->ataqueDeclarado(text.right(text.size() - 9));

        //enc - encerramento de rodada
        else if (text.startsWith("<tipo>enc"))
            emit this->turnoEncerrado(text.right(text.size() - 9));

        //vob - verificar objetivo
        else if (text.startsWith("<tipo>vob"))
            emit this->verificarObjetivo(text.right(text.size() - 9));
    }
}

void Connection::terminarEspera()
{
    disconnect (this->server, SIGNAL(newConnection()), this, SLOT(setSocket()));
    this->iniciarJogo();
}

void Connection::iniciarJogo()
{
    QString text;

    //sorteio da cor do jogador
    for (int i = 0; i < this->sockets_list.size(); i++) {
        this->sockets_list.at(i)->cor = this->cores->sortearCor();
        text = "<tipo>cor<jogador>" + this->sockets_list.at(i)->nome_jogador + "<cor>" + this->sockets_list.at(i)->cor;
        this->sendMessage(text);
    }

    //distribuicao de objetivos
    for (int i = 0; i < this->sockets_list.size(); i++) {
        this->sockets_list.at(i)->objetivo = objetivos->sortearObjetivo();
        text = "<tipo>mob<texto>" + this->sockets_list.at(i)->objetivo->texto;
        this->sendMessage(this->sockets_list.at(i), text);
    }

    int jogador_atual = 0;
    while (this->paises->paises_disponiveis.size() != 0) {
        Pais* pais = this->paises->sortearPais();
        QString text = "<tipo>spa<pais>" + pais->nome + "<jogador>" + this->sockets_list.at(jogador_atual)->nome_jogador +
               "<tropas>2<cor>" + this->sockets_list.at(jogador_atual)->cor;
        this->sendMessage(text);
        this->sockets_list.at(jogador_atual)->num_paises ++;
        pais->participante = this->sockets_list.at(jogador_atual);
        jogador_atual++;
        if (jogador_atual == this->sockets_list.size())
            jogador_atual = 0;
    }
    for (int i = 0; i < this->sockets_list.size(); i++)
        this->sockets_list.at(i)->num_tropas_rodada = this->sockets_list.at(i)->num_paises/2;

    //primeiro jogador da lista eh o primeiro a jogar
    this->sendMessage("<tipo>vez<jogador>" + this->sockets_list.at(0)->nome_jogador +
                      "<novas_tropas>" + QString::number(this->sockets_list.at(0)->num_tropas_rodada));
}

bool Connection::hasDataToRead ()
{
    bool data = false;
    for (int i = 0; i < this->sockets_list.size() && !data; i++)
        if (this->sockets_list.at(i)->socket->bytesAvailable() != 0)
            data = true;
    return data;
}

void Connection::passarVez(QString texto)
{
    QString nome_jogador = texto.split("<jogador>").at(1);
    int index;

    for (index = 0; index < this->sockets_list.size(); index++)
        if (this->sockets_list.at(index)->nome_jogador == nome_jogador)
            break;

    index++;

    if (index == this->sockets_list.size()) {

        for (int i = 0; i < this->sockets_list.size(); i++)
            this->sockets_list.at(i)->num_tropas_rodada = this->sockets_list.at(i)->num_paises/2;
        index = 0;
    }

    this->sendMessage("<tipo>vez<jogador>" + this->sockets_list.at(index)->nome_jogador +
                      "<novas_tropas>" + QString::number(this->sockets_list.at(index)->num_tropas_rodada));
}

void Connection::checarObjetivo(QString texto)
{
    QString nome_jogador = texto.right (texto.size() - 14);
    QStringList paises_jogador = this->paises->paisesDoJogador(nome_jogador);
    int index;

    for (index = 0; index < this->sockets_list.size(); index++)
        if (this->sockets_list.at(index)->nome_jogador == nome_jogador)
            break;

    bool resultado_objetivo = this->sockets_list.at(index)->objetivo->objetivoConcluido(paises_jogador);

    if (resultado_objetivo)
        this->sendMessage("<tipo>fim<mensagem>Jogador " + this->sockets_list.at(index)->nome_jogador + " venceu!");
    else
        this->sendMessage(this->sockets_list.at(index), "<tipo>ona<mensagem>Objetivo nao alcancado");
}
